﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using AllInOnePluginBL.Helpers;
using PluginDB;

namespace AllInOnePluginBL.SiteScrappers
{
    public class SartababritParserJob : BaseSiteScrapper
    {
        #region Private Members
        private const string DEFAULT_URL = "http://sartababrit.blogspot.com/";
        private const string NAME = "Sartababrit";

        private class CategoryItem
        {
            public string Url { get; set; }
            public string Name { get; set; }
            public string Items { get; set; }
        }
        #endregion

        #region Ctor
        public SartababritParserJob() : base(NAME)
        {
        } 
        #endregion

        #region Implementation of IJob
        public override void Execute(int pagesToScan)
        {
            _log.Info(string.Format("Start Executing SartababritParserJob at {0}", DateTime.Now.ToString("r")));

            try
            {
                var pageContent = Utils.GetPage(DEFAULT_URL, Encoding.UTF8);
                var categoriesItems = GetCategoriesLinks(pageContent);

                //If site not exists in db then scan all site for first time
                if (!_pluginDBHandler.IsSiteExists(NAME))
                {
                    pagesToScan = 0;
                }
                
                pagesToScan = (pagesToScan == 0) ? -1 : pagesToScan;

                foreach (var categoryItem in categoriesItems)
                {
                    ReadMovies(categoryItem, pagesToScan);
                }
            }
            catch (Exception ex)
            {
                _log.ErrorException("Error while SartababritParserJob::Execute", ex);
            }

            _log.Info(string.Format("End Executing SartababritParserJob at {0}", DateTime.Now.ToString("r")));
        }
        #endregion

        #region Private Methods
        private IEnumerable<CategoryItem> GetCategoriesLinks(string pageContent)
        {
            const string CATEGORIES_REG_EX = "<div class='widget-content list-label-widget-content'>.*?<ul>(.+?)</ul>";
            const string CATEGORY_REGEX = "<li>.*?<a dir='rtl' href='(.+?)'>(.+?)</a>.*?<span dir='ltr'>\\((.+?)\\)</span>.*?</li>";

            var categoriesContent = Regex.Match(pageContent, CATEGORIES_REG_EX, RegexOptions.Singleline).Value;

            var matchs = Regex.Matches(categoriesContent, CATEGORY_REGEX, RegexOptions.Singleline);

            return (from Match match in matchs
                    select new CategoryItem
                        {
                            Url = match.Groups[1].Value,
                            Name = match.Groups[2].Value,
                            Items = match.Groups[3].Value
                        }).ToList();
        }

        private void ReadMovies(CategoryItem categoryItem, int pagesToScan)
        {
            try
            {
                var fullUrl = string.Format("{0}?max-results={1}", categoryItem.Url, categoryItem.Items);
                var categoryContent = Utils.GetPage(fullUrl, Encoding.UTF8);
                var itemsContent = categoryContent.Split(new[] { "<div class='wrapfullpost'>" },
                                                  StringSplitOptions.RemoveEmptyEntries);

                if(pagesToScan == 0)
                {
                    return;
                }
                
                var pagesScaned = pagesToScan;
                foreach (var itemContent in itemsContent)
                {
                    AddVideo(itemContent);
                }

                const string OLD_RECORDS_REGEX = "<a class='blog-pager-older-link' href='(.+?)'";
                var oldCategoriesLink = Regex.Match(categoryContent, OLD_RECORDS_REGEX, RegexOptions.Singleline).Groups[1].Value;
                if (!string.IsNullOrEmpty(oldCategoriesLink))
                {
                    ReadMovies(new CategoryItem
                                   {
                                       Url = oldCategoriesLink,
                                       Items = categoryItem.Items
                                   }, pagesScaned-1);
                }
            }
            catch (Exception ex)
            {
                _log.ErrorException(string.Format("Error in SartababritParserJob::GetMovies. url:{0}", categoryItem.Url), ex);
            }
        }

        private void AddVideo(string itemContent)
        {
            try
            {
                var video = GetVideo(itemContent);
                if (video == null) return;

                if (video.Links.Count == 0)
                {
                    _log.Warn("{0} Has no links. not saving it", video.VideoName);
                    return;
                }

                _pluginDBHandler.AddNewVideo(video);
            }
            catch (Exception ex)
            {
                _log.ErrorException("Error in SartababritParserJob::AddVideo.", ex);
            }
        }

        private string GetName(string pageContent)
        {
            const string NAME_REGEX = "<h3 class='post-title entry-title'>.*?<a href='(.+?)'>(.+?)</a>.*?</h3>";
            var name = Regex.Match(pageContent, NAME_REGEX, RegexOptions.Singleline).Groups[2].Value;
            return name;
        }

        private string GetVideoUrl(string pageContent)
        {
            const string NAME_REGEX = "<h3 class='post-title entry-title'>.*?<a href='(.+?)'>(.+?)</a>.*?</h3>";
            var url = Regex.Match(pageContent, NAME_REGEX, RegexOptions.Singleline).Groups[1].Value;
            return url;
        }

        private string GetImage(string pageContent)
        {
            const string IMAGE_REGEX = "<div class='post-body entry-content'>.*?<img.*?src=\"(.+?)\"";
            var image = Regex.Match(pageContent, IMAGE_REGEX, RegexOptions.Singleline).Groups[1].Value.ToLower();
            if( !image.Contains(".jpg") &&
                !image.Contains(".bmp") &&
                !image.Contains(".gif"))
            {
                return string.Empty;
            }

            return image;
        }

        private string GetPlot(string pageContent)
        {
            const string PLOT_REGEX = "<div class='post-body entry-content'>.*?<br />(.+?)<br />";
            var plot = Regex.Match(pageContent, PLOT_REGEX, RegexOptions.Singleline).Groups[1].Value.ToLower();
            if (plot.Contains(">") ||
                plot.Contains("<"))
            {
                return string.Empty;
            }

            return plot;
        }

        private PluginVideoInfo GetVideo(string itemContent)
        {
            var videoUrl = GetVideoUrl(itemContent);
            if (_pluginDBHandler.IsVideoExists(videoUrl)) return null;

            var videoName = GetName(itemContent);
            if (string.IsNullOrEmpty(videoName)) return null;

            var video = new PluginVideoInfo
            {
                VideoName = videoName,
                PluginUrl = videoUrl,
                SiteName = NAME,
                Categories = new List<string> { Common.GENERAL_CATEGORY_NAME },
                ImageUrl = GetImage(itemContent),
                Plot = GetPlot(itemContent)
            };

            #region Get Links
            var links = Utils.GetMovieLinks(itemContent);
            foreach (var link in links)
            {
                video.Links.Add(new PluginVideoInfo.Link
                {
                    LinkURL = link,
                    SourceName = GetLinkSource(link)
                });
            }
            return video;
            #endregion
        }

        private string GetLinkSource(string link)
        {
            const string expression = @"^([a-zA-Z]+:\/\/)?([^\/]+)\/.*?$";
            var match = Regex.Match(link, expression, RegexOptions.Singleline);
            if (match.Success)
            {
                var list = match.Groups[2].Value.Split('.');
                if (list[0] == "www")
                    return list[1];
                return list[0];

            }
            return string.Empty;
        }
        #endregion
    }
}
